package com.yuexia.yxim.common.code;

import com.sun.media.sound.InvalidFormatException;
import com.yuexia.yxim.common.bean.msg.ProtoMsg;
import com.yuexia.yxim.common.enums.ProtoInstant;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @Author: yue_xia
 * 1.首先读取长度，如果长度不够则终止读取
 * 2.读取魔数，版本号等其他字段，并验证
 * 3.按照长度读取内容，如果内容字节数不够，则恢复之前的起始位置，然后终止读取
 * @Date: 2020/5/31 8:56 下午
 */
public class ProtobufDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx,
                          ByteBuf in,
                          List<Object> out) throws Exception {

        //标记一下当前的读指针位置位置
        in.markReaderIndex();

        //判断包头长度
        if (in.readableBytes() <2) {
            //不够包头
            return;
        }

        //读取魔数
        short magic = in.readShort();
        if (ProtoInstant.MAGIC_CODE != magic) {
            String error = "客户端发送的魔数错误:" + ctx.channel().remoteAddress();
            throw new InvalidFormatException(error);
        }

        //读取版本号 todo 版本号处理
        short version = in.readShort();

        //读取消息长度
        int length = in.readInt();

        if (length < 0) {
            //非法数据，关闭连接
            ctx.close();
        }

        if (length > in.readableBytes()) {
            //读取到的消息长度如果小于传过来的消息长度  则说明消息没有发完，重置读指针
            in.resetReaderIndex();
            return;
        }

        //读取内容 读取出来是一个字节数组
        byte[] array;
        if (in.hasArray()) {
            //堆缓存
            ByteBuf slice = in.slice();
            array = slice.array();
        }else {
            array = new byte[length];
            in.readBytes(array, 0, length);
        }

        //字节数组转换为对象
        ProtoMsg.Message message = ProtoMsg.Message.parseFrom(array);

        if (message != null) {
            out.add(message);
        }

    }
}
